package ph.com.gs3.formalistics.model.valueobjects.application;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

public class Document {

	public static final String TAG = Document.class.getSimpleName();

	private JSONObject documentRawJSON;

	private String dbId;
	private String webId;
	private String server;
	private String formWebId;

	private String trackingNumber;
	private String status;
	private String processorWebId;
	private String requestorWebId;

	private JSONObject actions;

	private String workflowId;
	private String currentNodeId;

	private List<String> fieldsEnabled;
	private List<String> fieldsRequired;
	private List<String> fieldsHidden;

	private JSONObject fields;

	protected static final String[] systemFields = { "ID", "TrackNo", "Status", "Processor",
	        "Requestor", "LastAction", "DateCreated", "DateUpdated", "CreatedBy", "UpdatedBy",
	        "Unread", "Node_ID", "Workflow_ID", "fieldEnabled", "fieldRequired",
	        "fieldHiddenValues", "imported", "Repeater_Data", "Editor", "Viewer",
	        "middleware_process" };

	// =======================================================================
	// Builder Methods

	public static Document createDocumentFromJSON(JSONObject rawObject, String server,
	        String formWebId) throws JSONException {

		Document document = new Document();

		document.documentRawJSON = rawObject;
		document.server = server;
		document.formWebId = formWebId;

		// @formatter:off
		document = 	document.mapBasicFields()
							.mapActions()
							.mapFieldProperties()
							.mapFields();
		// @formatter:on

		return document;

	}

	public Document mapBasicFields() throws JSONException {

		// @formatter:off
		webId 			= documentRawJSON.getString("ID");
		trackingNumber 	= documentRawJSON.getString("TrackNo");
		status 			= documentRawJSON.getString("Status");
		processorWebId 	= documentRawJSON.getString("Processor");
		requestorWebId 	= documentRawJSON.getString("Requestor");
		
		workflowId		= documentRawJSON.getString("Workflow_ID");
		currentNodeId	= documentRawJSON.getString("Node_ID");
		// @formatter:on

		return this;

	}

	public Document mapActions() throws JSONException {

		String rawActions = documentRawJSON.getString("LastAction");
		actions = new JSONObject(rawActions);
		return this;

	}

	public Document mapFieldProperties() throws JSONException {

		JSONArray fieldsEnabledJSONArray = new JSONArray(documentRawJSON.getString("fieldEnabled"));
		fieldsEnabled = new ArrayList<String>();
		for (int i = 0; i < fieldsEnabledJSONArray.length(); i++) {
			fieldsEnabled.add(fieldsEnabledJSONArray.getString(i));
		}

		JSONArray fieldsRequiredJSONArray = new JSONArray(
		        documentRawJSON.getString("fieldRequired"));
		fieldsRequired = new ArrayList<String>();
		for (int i = 0; i < fieldsRequiredJSONArray.length(); i++) {
			fieldsRequired.add(fieldsRequiredJSONArray.getString(i));
		}

		JSONArray fieldsHiddenJSONArray = new JSONArray(
		        documentRawJSON.getString("fieldHiddenValues"));
		fieldsHidden = new ArrayList<String>();
		for (int i = 0; i < fieldsHiddenJSONArray.length(); i++) {
			fieldsHidden.add(fieldsHiddenJSONArray.getString(i));
		}

		return this;

	}

	public Document mapFields() throws JSONException {

		fields = Document.extractDataFieldsFromDocument(this);
		return this;
	}

	// =======================================================================
	// Parser & Extractor Methods

	/**
	 * Not yet tested
	 * 
	 * @param document
	 * @return
	 * @throws JSONException
	 */
	public static JSONObject extractDataFieldsFromDocument(Document document) throws JSONException {

		JSONObject data = new JSONObject();
		JSONObject documentFields = document.getDocumentRawJSON();

		List<String> systemFieldsList = Arrays.asList(systemFields);

		Iterator<?> keys = documentFields.keys();

		while (keys.hasNext()) {
			String key = (String) keys.next();
			if (!systemFieldsList.contains(key)) {
				// throws JSONException
				data.put(key, documentFields.get(key));
			}
		}

		return data;

	}

	// =======================================================================
	// Getters & Setters

	@Override
	public String toString() {
		return "Document " + webId + " from " + server;
	}

	public String getDbId() {
		return dbId;
	}

	public void setDbId(String dbId) {
		this.dbId = dbId;
	}

	public String getWebId() {
		return webId;
	}

	public void setWebId(String webId) {
		this.webId = webId;
	}

	public String getServer() {
		return server;
	}

	public void setServer(String server) {
		this.server = server;
	}

	public String getFormWebId() {
		return formWebId;
	}

	public void setFormWebId(String formWebId) {
		this.formWebId = formWebId;
	}

	public String getTrackingNumber() {
		return trackingNumber;
	}

	public void setTrackingNumber(String trackingNumber) {
		this.trackingNumber = trackingNumber;
	}

	public String getStatus() {
		return status;
	}

	public void setStatus(String status) {
		this.status = status;
	}

	public String getProcessorWebId() {
		return processorWebId;
	}

	public void setProcessorWebId(String processorWebId) {
		this.processorWebId = processorWebId;
	}

	public String getRequestorWebId() {
		return requestorWebId;
	}

	public void setRequestorWebId(String requestorWebId) {
		this.requestorWebId = requestorWebId;
	}

	public JSONObject getActions() {
		return actions;
	}

	public void setActions(JSONObject actions) {
		this.actions = actions;
	}

	public String getWorkflowId() {
		return workflowId;
	}

	public void setWorkflowId(String workflowId) {
		this.workflowId = workflowId;
	}

	public String getCurrentNodeId() {
		return currentNodeId;
	}

	public void setCurrentNodeId(String currentNodeId) {
		this.currentNodeId = currentNodeId;
	}

	public List<String> getFieldsEnabled() {
		return fieldsEnabled;
	}

	public void setFieldsEnabled(List<String> fieldsEnabled) {
		this.fieldsEnabled = fieldsEnabled;
	}

	public List<String> getFieldsRequired() {
		return fieldsRequired;
	}

	public void setFieldsRequired(List<String> fieldsRequired) {
		this.fieldsRequired = fieldsRequired;
	}

	public List<String> getFieldsHidden() {
		return fieldsHidden;
	}

	public void setFieldsHidden(List<String> fieldsHidden) {
		this.fieldsHidden = fieldsHidden;
	}

	public JSONObject getDocumentRawJSON() {
		return documentRawJSON;
	}

	public void setDocumentRawJSON(JSONObject fields) {
		this.documentRawJSON = fields;
	}

	public JSONObject getFields() {
		return fields;
	}

	public void setFields(JSONObject fields) {
		this.fields = fields;
	}

}
